package {{ package.lower_snake_case }};

import io.grpc.ManagedChannel;
import io.grpc.okhttp.OkHttpChannelBuilder;
import io.grpc.stub.StreamObserver;
import io.reactivex.Completable;
import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.Scheduler;
import io.reactivex.Single;
import io.reactivex.schedulers.Schedulers;
import java.lang.String;
import java.util.List;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class {{ plugin_name.upper_camel_case }} {
  private static final Logger logger = LoggerFactory.getLogger({{ plugin_name.upper_camel_case }}.class);

  private ManagedChannel channel;
  private {{ plugin_name.upper_camel_case }}ServiceGrpc.{{ plugin_name.upper_camel_case }}ServiceStub stub;
  private Scheduler scheduler;

  public {{ plugin_name.upper_camel_case }}() {
    this("127.0.0.1", 50051);
  }

  public {{ plugin_name.upper_camel_case }}(String host, int port) {
    this(createChannel(host, port));
  }

  private static ManagedChannel createChannel(String host, int port) {
    logger.trace("Building channel to " + host + ":" + port);

    return OkHttpChannelBuilder.forAddress(host, port)
        .usePlaintext()
        .build();
  }

  private {{ plugin_name.upper_camel_case }}(ManagedChannel channel) {
    this.channel = channel;
    stub = {{ plugin_name.upper_camel_case }}ServiceGrpc.newStub(channel);
    scheduler = Schedulers.trampoline();
  }

  public void dispose() {
    this.channel.shutdown();
  }

  {% if has_result %}
  public class {{ plugin_name.upper_camel_case }}Exception extends Exception {
    private {{ plugin_name.upper_camel_case }}Result.Result code;
    private String description;

    public {{ plugin_name.upper_camel_case }}Exception({{ plugin_name.upper_camel_case }}Result.Result code, String description) {
      super(code + ": " + description);

      this.code = code;
      this.description = description;
    }

    public {{ plugin_name.upper_camel_case }}Result.Result getCode() {
      return this.code;
    }

    public String getDescription() {
      return this.description;
    }
  }
  {% endif %}

{%- for enum in enums %}
{{ indent(enum, 1) }}
{%- endfor %}

{% for struct in structs %}
{{ indent(struct, 1) }}
{% endfor %}

{%- for method in methods %}
{{ indent(method, 1) }}
{%- endfor %}
}
